/**
 * 综合图像优化工具
 * 
 * 功能：
 * 1. 自动查找和优化大体积图片
 * 2. 支持多种格式转换(PNG/JPG→WebP)
 * 3. 自动创建占位图
 * 4. 智能更新代码引用
 * 5. 支持批处理和报告生成
 */

const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const crypto = require('crypto');

// 配置项
const config = {
  // 需要扫描的图片目录
  imageDirs: [
    'images',
    'src/device_types/seawater_lamp/images',
    'src/device_types/freshwater_lamp/images',
    'assets/icons'
  ],
  // 图片格式
  imageExts: ['.png', '.jpg', '.jpeg', '.gif'],
  // 需要扫描的代码文件扩展名
  codeExts: ['.js', '.wxml', '.wxss', '.json'],
  // 大图片阈值（字节）
  largeImageThreshold: 100 * 1024, // 100KB
  // 超大图片阈值（字节）
  hugeImageThreshold: 1024 * 1024, // 1MB
  // WebP转换质量设置
  webpQuality: {
    default: 85,    // 默认质量
    large: 80,      // 大图质量
    huge: 75        // 超大图质量
  },
  // 占位图输出目录
  placeholderDir: 'images/placeholders',
  // 是否自动更新代码引用
  autoUpdateReferences: true,
  // 排除目录
  excludeDirs: ['node_modules', '.git', 'miniprogram_npm', 'webp-tools']
};

// 工具类
class ImageOptimizer {
  constructor() {
    this.stats = {
      processed: 0,
      converted: 0,
      placeholdersCreated: 0,
      referencesUpdated: 0,
      errors: 0,
      totalSizeBefore: 0,
      totalSizeAfter: 0
    };
    
    this.largeImages = [];
    this.conversionMap = new Map();
    this.checkDependencies();
  }

  // 检查依赖
  checkDependencies() {
    try {
      // 检查WebP工具
      if (process.platform === 'win32') {
        try {
          execSync('cwebp -version');
          console.log('✅ cwebp 已安装');
        } catch (e) {
          if (fs.existsSync('webp-tools/libwebp-1.5.0-windows-x64/bin/cwebp.exe')) {
            console.log('✅ 在项目目录中找到cwebp');
            process.env.PATH = `${process.env.PATH};${path.resolve('webp-tools/libwebp-1.5.0-windows-x64/bin')}`;
          } else {
            console.error('❌ 未找到cwebp，请安装：https://developers.google.com/speed/webp/download');
            process.exit(1);
          }
        }
      } else {
        try {
          execSync('cwebp -version');
          console.log('✅ cwebp 已安装');
        } catch (e) {
          console.error('❌ 未找到cwebp');
          console.log('请使用以下命令安装:');
          console.log('  Mac: brew install webp');
          console.log('  Linux: sudo apt install webp');
          process.exit(1);
        }
      }
    } catch (error) {
      console.error(`检查依赖时出错: ${error.message}`);
      process.exit(1);
    }
  }

  // 递归查找图片文件
  findImageFiles() {
    console.log('🔍 扫描图片文件...');
    const imageFiles = [];

    for (const dir of config.imageDirs) {
      if (!fs.existsSync(dir)) {
        console.warn(`⚠️ 目录不存在: ${dir}`);
        continue;
      }
      
      this._findFilesRecursive(dir, config.imageExts, imageFiles);
    }
    
    console.log(`找到 ${imageFiles.length} 个图片文件`);
    return imageFiles;
  }

  // 递归查找文件辅助方法
  _findFilesRecursive(dir, extensions, fileList) {
    if (!fs.existsSync(dir)) return;
    
    const files = fs.readdirSync(dir);
    
    for (const file of files) {
      const filePath = path.join(dir, file);
      const stat = fs.statSync(filePath);
      
      if (stat.isDirectory() && !config.excludeDirs.some(excludeDir => filePath.includes(excludeDir))) {
        this._findFilesRecursive(filePath, extensions, fileList);
      } else if (stat.isFile() && extensions.includes(path.extname(filePath).toLowerCase())) {
        fileList.push(filePath);
      }
    }
  }

  // 分析图片并筛选大尺寸图片
  analyzeImages(imageFiles) {
    console.log('📊 分析图片大小...');
    
    for (const file of imageFiles) {
      try {
        const stats = fs.statSync(file);
        const sizeMB = stats.size / (1024 * 1024);
        this.stats.totalSizeBefore += stats.size;
        
        if (stats.size > config.largeImageThreshold) {
          this.largeImages.push({
            path: file,
            size: stats.size,
            sizeFormatted: this._formatSize(stats.size),
            isHuge: stats.size > config.hugeImageThreshold
          });
        }
      } catch (error) {
        console.error(`❌ 分析图片时出错 ${file}: ${error.message}`);
        this.stats.errors++;
      }
    }
    
    // 按大小排序
    this.largeImages.sort((a, b) => b.size - a.size);
    
    console.log(`发现 ${this.largeImages.length} 个大尺寸图片（> ${this._formatSize(config.largeImageThreshold)}）`);
    
    // 打印前10个最大的图片
    if (this.largeImages.length > 0) {
      console.log('\n最大的图片:');
      this.largeImages.slice(0, 10).forEach((img, index) => {
        console.log(`${index + 1}. ${img.path} - ${img.sizeFormatted}`);
      });
    }
    
    return this.largeImages;
  }

  // 转换为WebP格式
  convertToWebP(image) {
    const inputFile = image.path;
    const outputFile = inputFile.replace(/\.(png|jpg|jpeg|gif)$/i, '.webp');
    
    // 根据图片大小选择质量
    let quality = config.webpQuality.default;
    if (image.isHuge) {
      quality = config.webpQuality.huge;
    } else if (image.size > config.largeImageThreshold) {
      quality = config.webpQuality.large;
    }
    
    try {
      // 确保输出目录存在
      this._ensureDirectoryExists(outputFile);
      
      // 使用cwebp转换
      const command = `cwebp -q ${quality} "${inputFile}" -o "${outputFile}"`;
      execSync(command, { stdio: 'ignore' });
      
      if (fs.existsSync(outputFile)) {
        const webpStats = fs.statSync(outputFile);
        const savings = ((image.size - webpStats.size) / image.size * 100).toFixed(2);
        
        this.conversionMap.set(inputFile, {
          original: inputFile,
          webp: outputFile,
          originalSize: image.size,
          webpSize: webpStats.size,
          savings: parseFloat(savings)
        });
        
        this.stats.converted++;
        this.stats.totalSizeAfter += webpStats.size;
        
        console.log(`✅ 已转换: ${inputFile} → ${outputFile}`);
        console.log(`   原始: ${this._formatSize(image.size)} → WebP: ${this._formatSize(webpStats.size)} (节省 ${savings}%)`);
        
        return {
          success: true,
          original: inputFile,
          webp: outputFile,
          savings: parseFloat(savings)
        };
      }
    } catch (error) {
      console.error(`❌ 转换失败 ${inputFile}: ${error.message}`);
      this.stats.errors++;
      return { success: false, error: error.message };
    }
  }

  // 生成占位图 - 对于大图片自动生成小体积占位图
  generatePlaceholder(image) {
    // 仅为超大图片创建占位图
    if (!image.isHuge) return null;
    
    try {
      // 确保占位图目录存在
      this._ensureDirectoryExists(path.join(config.placeholderDir, 'dummy.txt'));
      
      // 获取文件名（不含路径和扩展名）
      const baseName = path.basename(image.path, path.extname(image.path));
      const placeholderFile = path.join(config.placeholderDir, `${baseName}_placeholder.svg`);
      
      // 随机生成浅色背景
      const randomColor = () => {
        const r = Math.floor(Math.random() * 20 + 235);
        const g = Math.floor(Math.random() * 20 + 235);
        const b = Math.floor(Math.random() * 20 + 235);
        return `#${r.toString(16)}${g.toString(16)}${b.toString(16)}`;
      };
      
      // 随机生成更深一些的前景色
      const randomFgColor = () => {
        const r = Math.floor(Math.random() * 40 + 180);
        const g = Math.floor(Math.random() * 40 + 180);
        const b = Math.floor(Math.random() * 40 + 180);
        return `#${r.toString(16)}${g.toString(16)}${b.toString(16)}`;
      };
      
      // 生成唯一hash值作为图片标识符
      const hash = crypto.createHash('md5').update(image.path).digest('hex').substring(0, 6);
      
      // 创建简单SVG占位图
      const svgContent = `<svg width="400" height="300" xmlns="http://www.w3.org/2000/svg">
  <rect width="100%" height="100%" fill="${randomColor()}"/>
  <rect x="150" y="100" width="100" height="100" fill="${randomFgColor()}"/>
  <text x="50%" y="50%" font-family="Arial" font-size="24" text-anchor="middle" fill="#808080">加载中...</text>
  <text x="50%" y="70%" font-family="Arial" font-size="12" text-anchor="middle" fill="#a0a0a0">${hash}</text>
</svg>`;
      
      fs.writeFileSync(placeholderFile, svgContent);
      this.stats.placeholdersCreated++;
      
      console.log(`✅ 已创建占位图: ${placeholderFile}`);
      
      return {
        original: image.path,
        placeholder: placeholderFile
      };
    } catch (error) {
      console.error(`❌ 创建占位图失败 ${image.path}: ${error.message}`);
      this.stats.errors++;
      return null;
    }
  }

  // 查找代码文件
  findCodeFiles() {
    console.log('🔍 扫描代码文件...');
    const codeFiles = [];
    
    this._findFilesRecursive('.', config.codeExts, codeFiles);
    
    console.log(`找到 ${codeFiles.length} 个代码文件`);
    return codeFiles;
  }

  // 更新代码中的图片引用
  updateImageReferences(codeFiles) {
    if (!config.autoUpdateReferences || this.conversionMap.size === 0) {
      return;
    }
    
    console.log('✏️ 更新代码中的图片引用...');
    
    let updatedFiles = 0;
    
    for (const file of codeFiles) {
      try {
        let content = fs.readFileSync(file, 'utf8');
        let hasChanges = false;
        
        for (const [originalPath, conversion] of this.conversionMap.entries()) {
          // 尝试多种路径形式匹配（相对路径、绝对路径等）
          const pathVariations = this._generatePathVariations(originalPath);
          
          for (const pathVar of pathVariations) {
            // 生成对应的WebP路径变体
            const webpPathVar = pathVar.replace(/\.(png|jpg|jpeg|gif)$/i, '.webp');
            
            // 匹配各种引用模式
            const patterns = [
              { pattern: new RegExp(`(['"])${this._escapeRegExp(pathVar)}(['"])`, 'g'), replacement: `$1${webpPathVar}$2` },
              { pattern: new RegExp(`src=['"](${this._escapeRegExp(pathVar)})['"](\\s|\>)`, 'g'), replacement: `src="${webpPathVar}"$2` },
              { pattern: new RegExp(`background(-image)?:\\s*url\\(['"](${this._escapeRegExp(pathVar)})['"](\\s*)\\)`, 'g'), replacement: `background$1: url("${webpPathVar}")` }
            ];
            
            for (const { pattern, replacement } of patterns) {
              if (pattern.test(content)) {
                content = content.replace(pattern, replacement);
                hasChanges = true;
              }
            }
          }
        }
        
        if (hasChanges) {
          fs.writeFileSync(file, content, 'utf8');
          updatedFiles++;
          this.stats.referencesUpdated++;
          console.log(`✅ 已更新引用: ${file}`);
        }
      } catch (error) {
        console.error(`❌ 更新引用失败 ${file}: ${error.message}`);
        this.stats.errors++;
      }
    }
    
    console.log(`共更新了 ${updatedFiles} 个文件中的图片引用`);
  }

  // 生成优化报告
  generateReport() {
    console.log('\n📝 生成优化报告...');
    
    const reportContent = `# 图片优化报告

## 优化摘要

- 处理时间: ${new Date().toLocaleString()}
- 扫描图片总数: ${this.stats.processed}
- 转换为WebP: ${this.stats.converted} 个文件
- 生成占位图: ${this.stats.placeholdersCreated} 个文件
- 更新代码引用: ${this.stats.referencesUpdated} 个文件
- 错误数量: ${this.stats.errors}

## 空间节省

- 转换前总大小: ${this._formatSize(this.stats.totalSizeBefore)}
- 转换后总大小: ${this._formatSize(this.stats.totalSizeAfter)}
- 节省空间: ${this._formatSize(this.stats.totalSizeBefore - this.stats.totalSizeAfter)} (${((this.stats.totalSizeBefore - this.stats.totalSizeAfter) / this.stats.totalSizeBefore * 100).toFixed(2)}%)

## 优化详情

| 原始文件 | 原始大小 | WebP文件 | WebP大小 | 节省比例 |
|---------|---------|---------|---------|---------|
${Array.from(this.conversionMap.values()).map(conversion => {
  return `| ${conversion.original} | ${this._formatSize(conversion.originalSize)} | ${conversion.webp} | ${this._formatSize(conversion.webpSize)} | ${conversion.savings.toFixed(2)}% |`;
}).join('\n')}

## 占位图生成

以下大图片已生成占位图:

${Array.from(this.conversionMap.keys())
  .filter(key => this.conversionMap.get(key).originalSize > config.hugeImageThreshold)
  .map(key => `- ${key} → ${path.join(config.placeholderDir, path.basename(key, path.extname(key)) + '_placeholder.svg')}`)
  .join('\n')}

## 使用建议

### 延迟加载大图片

对于大于1MB的图片，建议使用占位图和延迟加载:

\`\`\`js
Page({
  data: {
    imageLoaded: false,
    imageSrc: '',
    placeholderSrc: '/images/placeholders/图片名_placeholder.svg'
  },
  
  onReady() {
    // 延迟加载大图片
    setTimeout(() => {
      this.setData({
        imageLoaded: true,
        imageSrc: '/实际图片路径.webp'
      });
    }, 300);
  }
})
\`\`\`

WXML:
\`\`\`html
<block wx:if="{{!imageLoaded}}">
  <image src="{{placeholderSrc}}" mode="aspectFit" class="image-placeholder"></image>
</block>
<block wx:else>
  <image src="{{imageSrc}}" mode="aspectFit" class="actual-image" lazy-load="true"></image>
</block>
\`\`\`

### 后续优化建议

1. 考虑使用云存储或CDN加速图片加载
2. 根据设备分辨率提供不同尺寸图片
3. 合并小图标为雪碧图减少请求数
`;

    // 保存报告到文件
    const reportFile = 'docs/reports/image_optimization_report.md';
    this._ensureDirectoryExists(reportFile);
    fs.writeFileSync(reportFile, reportContent);
    
    console.log(`✅ 报告已生成: ${reportFile}`);
    
    return reportFile;
  }

  // 运行整个优化流程
  async run() {
    console.log('🚀 开始图片优化流程...\n');
    
    // 1. 查找所有图片
    const imageFiles = this.findImageFiles();
    this.stats.processed = imageFiles.length;
    
    // 2. 分析并筛选大图片
    const largeImages = this.analyzeImages(imageFiles);
    
    if (largeImages.length === 0) {
      console.log('未发现需要优化的大图片');
      return;
    }
    
    // 3. 转换大图片为WebP
    console.log('\n🔄 开始转换图片为WebP格式...');
    for (const image of largeImages) {
      this.convertToWebP(image);
      
      // 4. 为超大图片生成占位图
      if (image.isHuge) {
        this.generatePlaceholder(image);
      }
    }
    
    // 5. 查找代码文件
    const codeFiles = this.findCodeFiles();
    
    // 6. 更新代码中的图片引用
    this.updateImageReferences(codeFiles);
    
    // 7. 生成报告
    this.generateReport();
    
    // 8. 输出总结
    console.log('\n✨ 图片优化完成!');
    console.log(`转换了 ${this.stats.converted} 个图片为WebP格式`);
    console.log(`创建了 ${this.stats.placeholdersCreated} 个占位图`);
    console.log(`更新了 ${this.stats.referencesUpdated} 个文件中的图片引用`);
    console.log(`节省空间: ${this._formatSize(this.stats.totalSizeBefore - this.stats.totalSizeAfter)} (${((this.stats.totalSizeBefore - this.stats.totalSizeAfter) / this.stats.totalSizeBefore * 100).toFixed(2)}%)`);
  }

  // 辅助方法 - 确保目录存在
  _ensureDirectoryExists(filePath) {
    const dirname = path.dirname(filePath);
    if (fs.existsSync(dirname)) {
      return true;
    }
    
    this._ensureDirectoryExists(dirname);
    fs.mkdirSync(dirname);
  }

  // 辅助方法 - 格式化文件大小
  _formatSize(bytes) {
    if (bytes < 1024) {
      return `${bytes} B`;
    } else if (bytes < 1024 * 1024) {
      return `${(bytes / 1024).toFixed(2)} KB`;
    } else if (bytes < 1024 * 1024 * 1024) {
      return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
    } else {
      return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;
    }
  }

  // 辅助方法 - 转义正则表达式特殊字符
  _escapeRegExp(string) {
    return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
  }

  // 辅助方法 - 生成可能的路径变体
  _generatePathVariations(filepath) {
    const variations = [];
    
    // 原始路径
    variations.push(filepath);
    
    // 尝试不同的路径分隔符
    variations.push(filepath.replace(/\\/g, '/'));
    
    // 尝试移除开头的./
    if (filepath.startsWith('./')) {
      variations.push(filepath.substring(2));
    } else {
      // 尝试添加./
      variations.push('./' + filepath);
    }
    
    // 尝试使用/开头
    if (!filepath.startsWith('/')) {
      variations.push('/' + filepath);
    }
    
    // 获取不含路径的文件名
    const fileName = path.basename(filepath);
    variations.push(fileName);
    
    return variations;
  }
}

// 命令行参数处理
function parseArgs() {
  const args = process.argv.slice(2);
  const options = {
    autoUpdateReferences: config.autoUpdateReferences,
    placeholderDir: config.placeholderDir,
    help: false
  };
  
  for (let i = 0; i < args.length; i++) {
    const arg = args[i];
    
    if (arg === '--no-update-refs') {
      options.autoUpdateReferences = false;
    } else if (arg === '--placeholder-dir' && i + 1 < args.length) {
      options.placeholderDir = args[++i];
    } else if (arg === '--help' || arg === '-h') {
      options.help = true;
    }
  }
  
  if (options.help) {
    console.log(`
图片优化工具使用方法:

node utils/image_optimizer.js [选项]

选项:
  --no-update-refs     不自动更新代码中的图片引用
  --placeholder-dir    指定占位图保存目录
  --help, -h           显示帮助信息

示例:
  node utils/image_optimizer.js --placeholder-dir images/placeholders
`);
    process.exit(0);
  }
  
  // 更新配置
  config.autoUpdateReferences = options.autoUpdateReferences;
  config.placeholderDir = options.placeholderDir;
  
  return options;
}

// 主函数
async function main() {
  // 解析命令行参数
  parseArgs();
  
  // 创建并运行优化器
  const optimizer = new ImageOptimizer();
  await optimizer.run();
}

// 执行主函数
main().catch(error => {
  console.error(`❌ 执行出错: ${error.message}`);
  process.exit(1);
}); 